﻿
using hdb;

using Dapper;
using hentity;
using hq;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
namespace hwms {
    /**
   *┌────────────────────────────────────────────────┐
   *│　描    述：Component                                                    
   *│　作    者：sgj                                              
   *│　版    本：1.0                                              
   *│　创建时间：2020/9/2 11:28:16                        
   *└────────────────────────────────────────────────┘
   **/
    public  class InAreaGroupEngine<CS, CSD> :GkTransaction where CS : AbsCoreStock where CSD : AbsCoreStockDetail, new() {
        public String boxCode;
        public int stn;
      
     
        protected long itemClassifyId;
        protected long goodDiff;
        List<CoreClassifyArea> coreClassifyAreaList;

        List<long> areaList;
        List<CoreWhGroupStat> hisDiffList;
        MyDict<int ,double> craneTasks;

        MyDict<long ,int> priorityDict;


        
        private bool priority2 = false;//平均库位存放
        private bool priority3 = false;//垛机间入库最快
        void continueTask(IDbConnection conn ,IDbTransaction trans ,CoreTask ct) {


            String sql = "select * from Core_task_param where task_id=@taskId  and type={0} and status < {1} and status>{2} ";
            sql= String.Format(sql ,( int ) TaskParamType.托盘搬运 ,( int ) CoreTaskParamStatus.执行完成 ,( int ) CoreTaskParamStatus.删除);
            
            List<CoreTaskParam> list = conn.Query<CoreTaskParam>(sql ,new { taskId = ct.id } ,trans).ToList();
            if( list.Count > 0 ) {
                return;
            }
            CS cs = conn.GetById<CS>(ct.stockId ,trans);
            if( cs.status == ( int ) StockStatus.盘库中 ) {
                ParamContent pc = new ParamContent { };
                TaskPersistenceUtil.moveCoreTaskParam(conn ,trans ,pc ,ct.id ,stn ,ct.src ,0);
            }
        }
        protected override TransRes Execute(IDbConnection conn ,IDbTransaction tran) {
            List<CoreTask> coreTaskList = checkCodeInWork(conn ,tran);
            if( coreTaskList.Count == 1 ) {
                continueTask(conn ,tran ,coreTaskList[0]);
                return new TransRes();
            } else if( coreTaskList.Count > 1 ) {

                return new TransRes(true ,boxCode + "at" + stn + "working 不能入库!");
            }
            before(conn ,tran);
            CS cs = getStock(conn ,tran);

            if( cs.status != (int)StockStatus.库外 ) {
                return new TransRes(boxCode + "at" + stn + "状态不能入库!" + cs.status);
            }
            // 可能原来入库站台，与正式入库口不一直。
            cs.locId = stn;
            long stockId = cs.id;
            List<CSD> stockDetailsList = CsdUtil.GetStockDetailList<CSD>(conn ,tran ,stockId);
            long itemId = getItem( stockDetailsList);
            CoreWhGroup group= selectGroup(conn ,tran ,itemId);
            if( group == null ) {
                return new TransRes("货位获取异常");
            }
        
            long goodDiff = LocConfig.getGoodDiff(conn ,tran ,stockDetailsList[0] ,cs);
            TaskPersistenceUtil.createInTask(goodDiff,cs ,( int ) group.id ,conn ,tran);
  
            return afterIntask(conn ,tran ,cs ,stockDetailsList);
        }

        long getItem(List<CSD> stockDetailsList) {
            return stockDetailsList[0].itemId;
        }
        protected virtual TransRes afterIntask(IDbConnection conn ,IDbTransaction trans ,CS cs ,List<CSD> stockDetailsList) {
            return new TransRes();
        }
        protected virtual void before(IDbConnection connection ,IDbTransaction transaction) {
        }

        protected virtual List<CoreTask> checkCodeInWork(IDbConnection connection ,IDbTransaction transaction) {
            string sql = "select * from Core_Task where  status <9 and  status>0 ";

            if( !String.IsNullOrWhiteSpace(boxCode) ) {
                sql += "  and box_Code=@boxCode  ";
            } else {
                sql += "  and src =  " + stn;
            }
            List<CoreTask> coreTaskList = connection.Query<CoreTask>(sql ,new {
                boxCode
            } ,transaction).ToList();
            return coreTaskList;
        }

        public virtual CS getStock(IDbConnection Connection ,IDbTransaction transaction) {
            string sql = @"select * from Core_stock where  status in (0,1,2,3,4,5,6,7)   and box_Code=@boxCode  ";
            List<CS> stockList = Connection.Query<CS>(sql ,new {
                boxCode
            } ,transaction).ToList();
            ;
            if( stockList.Count == 0 ) {
                String info = boxCode + "没有库位异常stock!";
                throw new Exception(info);
            }
            if( stockList.Count > 1 ) {
                String info = boxCode + "重复的库位异常stock!";
                throw new Exception(info);
            }
            CS cs = stockList[0];
            return cs;
        }


    

        void init(IDbConnection conn ,IDbTransaction trans,long itemId) {
            string sql = @"select classify_Id classifyId from core_Item where id=@id ";
            itemClassifyId = conn.QueryUnique<long>(sql ,new { id = itemId } ,trans);
            if( itemClassifyId == 0 ) {
                throw new Exception(itemId + "的分类未找到");
            }
            loadCoreClassifyArea(itemClassifyId ,conn ,trans);
            goodDiff = getGroup(conn ,trans,itemId);
            
            priorityDict = new MyDict<long ,int>();
            areaList = new List<long>();
            for( int j = 0;j < coreClassifyAreaList.Count;j++ ) {
                CoreClassifyArea areaDto = coreClassifyAreaList[j];
                 if( areaDto.priority == 2 ) {
                    priority2 = true;
                } else if( areaDto.priority == 3 ) {
                    priority3 = true;
                }
                priorityDict.addOverride(areaDto.areaId ,areaDto.priority);
                areaList.Add(areaDto.areaId);
            }
            if( priority2 ) {
                String diff = "SELECT * FROM core_wh_group_stat where diff_key=@goodDiff";
                hisDiffList = conn.Query<CoreWhGroupStat>(diff ,new { goodDiff } ,trans).ToList();
            }
            if( priority3 ) {
                craneTasks = getCraneWork(conn ,trans);
            }
        }
        protected CoreWhGroup selectGroup(IDbConnection conn ,IDbTransaction trans , long itemId) {
            init(conn ,trans,itemId);


            String groupSql = "SELECT * FROM core_wh_group  where area_id in @areaList and max_stock>count_stock and wcs_auto_active=1";
            List<CoreWhGroup> groups = conn.Query<CoreWhGroup>(groupSql ,new { areaList = areaList.ToArray() } ,trans).ToList();
            double weight=0;
            CoreWhGroup group = null;
            foreach( var g in groups ) {
                int priority = priorityDict.getValue(g.areaId);
                long areaId = g.areaId;
                if( group!=null&& isFull(group) ) {
                    continue;
                }
                if( priority == 1 ) {//优先
                    group = g;
                    break;//起到优化作用，减少无意义循环
                } else if( priority == 2 ) {//平均
                    var w = getPriority2Per(group ,areaId);
                  
                    if( 0.9 - w > weight ) {
                        group = g;
                        weight = 0.9 - w;
                    }

                } else if( priority == 3 ) {//总体入库最快
                  
                    if( 0.9 - craneTasks.getValue(g.craneId) > weight ) {
                        group = g;
                        weight = 0.9 - craneTasks.getValue(g.craneId);
                    }
                }
                weight= locChangeWeight(itemClassifyId ,goodDiff,weight);
            }
            return group;
        }

        double getPriority2Per(CoreWhGroup group ,long areaId) {
            float count = 0;
            foreach( CoreWhGroupStat diff in hisDiffList ) {
                if( diff.areaId == areaId && diff.groupId == group.locGroup ) {
                    count += diff.countStock;
                }
            }
            float all = count + group.maxStock - group.countStock;
            return count / all;
        }
        void loadCoreClassifyArea(long itemClassifyId ,IDbConnection conn ,IDbTransaction trans) {
            string sql = @"select * from core_classify_Area  where classify_Id=@classifyId order by Priority ";
            //一个物料类别对应多个区域 查询物料优先放在哪个区域
            coreClassifyAreaList = conn.Query<CoreClassifyArea>(sql ,new {
                classifyId = itemClassifyId
            } ,trans).ToList();

        }
        MyDict<int ,double> getCraneWork(IDbConnection conn ,IDbTransaction trans) {
            String sql = @" SELECT crane_Id, sum(count_in) count_in ,  sum(count_ining) count_ining ,
                        sum(count_outin) count_outin ,sum(count_out) count_out FROM core_wh_group GROUP BY crane_Id ";
            List<CoreWhGroup> all = conn.Query<CoreWhGroup>(sql ,null ,trans).ToList();
            double sum = 1;
            foreach( CoreWhGroup g in all ) {
                sum += g.countIn + g.countOut + g.countOutin + g.countIning;
            }
            MyDict<int ,double> res = new MyDict<int ,double>();

            foreach( CoreWhGroup g in all ) {
                res.addOverride(g.craneId ,(g.countIn + g.countOut + g.countOutin + g.countIning) / sum);

            }
            return res;
        }
       

        protected virtual double locChangeWeight(long itemClassifyId ,long group,double weight) {
            return weight;
        }
        protected virtual bool isFull(CoreWhGroup item) {
            return item.maxStock <= item.countStock + 1;
        }
     
        protected virtual long getGroup(IDbConnection connection ,IDbTransaction transaction,long itemId) {
            return itemId;

        }
    }
}
